/*
 * fuseDef.c
 *
 *  Created on: 19/09/2011
 *      Author: meax
 */

#include "fuseDef.h"

/*******************************************************************/
/*	Variables Globales	*/

struct bootSector* bootSectorDisco;

/*	Sectores Reservados, Fat Compies	*/
extern unsigned char* bootAndFats;

extern int32_t cacheActiva;

/*******************************************************************/

static int pfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
{

	if(crearArchivo(path) == -1)
		return -ENOENT;

	return 0;

}

static int pfs_open(const char *path, struct fuse_file_info *fi)
{

	ListaDirectorios* file = abrirArchivo(path);

	if(file == NULL)
		return -ENOENT;


	if(!cacheActiva)
		liberarDirectorio(file);

	return 0;

}

static int pfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
{
	(void) fi;

	size_t retorno = leerArchivo(path, buf, size, offset);

	if(retorno == -1)
		return -ENOENT;

	return retorno;

}

static int pfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
{

	size_t retorno = escribirArchivo(path,buf, size, offset);

	if( retorno == -1)
		return -ENOENT;

	return retorno;

}

static int pfs_flush(const char *path, struct fuse_file_info *fi)
{
	//	cache
	ListaDirectorios* dir = abrirArchivo(path);

	if(dir == NULL)
		{
		/*	LOG	*/
		return -1;
		}

	if(cacheActiva)
		flushCacheDataForFile(path);

	else
		liberarDirectorio(dir);

	/*	persistir fat	*/
	//persistirFAT(bootSectorDisco);

	return 0;
}

static int pfs_release(const char *path, struct fuse_file_info *fi)
{
	//	cache
	ListaDirectorios* dir = abrirArchivo(path);

	if(dir == NULL)
		{
		/*	LOG	*/
		return -1;
		}

	if(cacheActiva)
		deleteCacheFileFlush(path);

	else
		liberarDirectorio(dir);

	/*	persistir fat	*/
	persistirFAT(bootSectorDisco);

	return 0;
}

static int pfs_truncate(const char *path, off_t newsize)
{
	if(truncarArchivo(path, newsize) == -1)
		return -ENOENT;

	return 0;
}

static int pfs_unlink(const char *path)
{
	if(borrarArchivo(path) == -1)
		return -ENOENT;

	return 0;
}

static int pfs_mkdir(const char *path, mode_t mode)
{
	if(crearCarpeta(path)==-1)
		return -ENOENT;

	return 0;
}

static int pfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{

    (void) offset;
    (void) fi;

	ListaDirectorios* ldir = malloc(sizeof(ListaDirectorios));
	lsdir(path, ldir);
	if(ldir==NULL)
		{free(ldir);return -ENOENT;}

	ListaDirectorios* pasaje;

	//	directorio vacio
	if((strcmp(path, "/") == 0) && (ldir -> directorio == NULL))
		{
	    filler(buf, ".", NULL, 0);
	    filler(buf, "..", NULL, 0);
	    liberarDirectorio(ldir);
		return 0;
		}

	char* nombreDir = malloc(sizeof(char)*20);

	do{
		//	entrada sin LFN
		if(ldir -> nombreLargo != NULL)
			strcpy(nombreDir, ldir -> nombreLargo);

		else
			{
			char* nombreShort = malloc(sizeof(char)*20);
			traerNombreShort(ldir -> directorio, nombreShort);
			strcpy(nombreDir, nombreShort);
			free(nombreShort);
			}

		if(filler(buf, nombreDir, NULL,0)!=0)
			return -ENOMEM;

		pasaje = (ListaDirectorios*)ldir -> siguiente;
		liberarDirectorio(ldir);
		ldir=pasaje;

	}while(ldir!= NULL);

	free(ldir);
	free(nombreDir);
	return 0;

}

static int pfs_rmdir(const char *path)
{

	if(borrarCarpeta(path) ==-1)
		return -ENOENT;

	return 0;
}

static int pfs_getattr(const char *path, struct stat *statbuf)
{

	if(strstr(path, ".Trash") != NULL)
		return -ENOENT;

	if(strstr(path, ".svn") != NULL)
		return -ENOENT;

	if(strstr(path, ".hidden") != NULL)
		return -ENOENT;

	if(strcmp("/", path) == 0)
		{
		statbuf -> st_mode = S_IFDIR | 0777;
      	statbuf -> st_nlink = 2;
		return 0;
		}

	ListaDirectorios* file = abrirArchivo(path);

	if(file == NULL)
		return -ENOENT;

	if((file -> directorio -> DIR_Attr & ATTR_DIRECTORY) == ATTR_DIRECTORY)
		{
		statbuf -> st_mode = S_IFDIR | 0777;
		statbuf -> st_nlink = 2;
		}

	else
		{
		statbuf -> st_mode = S_IFREG | 0666;
		statbuf -> st_nlink = 1;
        statbuf -> st_size = file->directorio->DIR_FileSize;
		}

	if(!cacheActiva)
		liberarDirectorio(file);

	return 0;

}

static int pfs_rename(const char *path, const char *newpath)
{
	if (renombrar(path, newpath) == -1)
		return -ENOENT;

	return 0;
}

static struct fuse_operations pfs_oper = {

	.create = pfs_create,
	.open = pfs_open,
	.read = pfs_read,
	.write = pfs_write,
	.flush = pfs_flush,
	.release = pfs_release,
	//.ftruncate = pfs_ftruncate,
	.truncate = pfs_truncate,
	.unlink = pfs_unlink,
	.mkdir = pfs_mkdir,
	.readdir = pfs_readdir,
	.rmdir = pfs_rmdir,
	//.fgetattr = pfs_fgetattr,
	.getattr = pfs_getattr,
	.rename = pfs_rename,

};

int32_t iniciarFuse(int argc, char* argv[] )
{

	bootSectorDisco = malloc(sizeof(struct bootSector));

	struct FSInfo* fileSystemInfo = malloc(sizeof(struct FSInfo));

	int res;

	res = leerBootSector(bootSectorDisco);

	if (res == -1)
		{escribir_logfile(NOMPS, 0, ERROR, "Mal Boot Sector"); return -1;}

//	res = leerFileSystemInfo(bootSectorDisco -> BPB_FSInfo, fileSystemInfo, bootSectorDisco);

	if (res == -1)
		{escribir_logfile(NOMPS, 0, ERROR, "NO es un sector FSInfor"); return -1;}

	printf("Bytes por sectores: %i\n", bootSectorDisco -> BPB_BytsPerSec);

	printf("Sectores por cluster: %i\n", bootSectorDisco -> BPB_SecPerClus);

	printf("Bytes por cluster: %i\n", bootSectorDisco -> BPB_SecPerClus * bootSectorDisco -> BPB_BytsPerSec);

	printf("Tamaño de la FAT: %i\n", bootSectorDisco -> BPB_FATSz32);

	printf("Total Sectores: %i\n", bootSectorDisco -> BPB_TotSec32 );

	printf("FirstDataSector: %i\n",firstDataSector(bootSectorDisco));

	printf("Primer Sector del CLuster 2: %i\n", firstSectorofCluster(bootSectorDisco, 2));

	printf("Data sectores: %i\n", totalDataSec(bootSectorDisco));

	printf("Cantidad de Clusters de data: %i\n", cantidadClustersData(bootSectorDisco));

	uint32_t sectoresPrincipales = firstDataSector(bootSectorDisco);
	//	le saco una fat
	sectoresPrincipales -= bootSectorDisco ->BPB_FATSz32;

	//bootAndFats = malloc(sizeof(char) * sectoresPrincipales * bootSectorDisco -> BPB_BytsPerSec);

	bufferPrincipalBootFats(bootSectorDisco, bootAndFats);

	printf("Clusters Libres: %i\n", cantidadClustersLibres(bootSectorDisco));

	printf("Clusters ocupados: %i\n", cantidadClustersData(bootSectorDisco) - cantidadClustersLibres(bootSectorDisco));

	printf("Last Free Cluster known: %i \n", fileSystemInfo -> FSI_Free_Count);

	printf("EOC: %02x\n", traerElEOC(bootSectorDisco, bootAndFats));

	printf("Root Cluster: %i\n", bootSectorDisco -> BPB_RootClus);

	printf("Entrada FAT root cluster: %02x\n\n", leerEntradaFAT(bootSectorDisco, bootSectorDisco -> BPB_RootClus));

	/*mostrarEntradasFat(bootSectorDisco);*/

	escribir_logfile(NOMPS, 0, INFO, "File System Operable");

	/*	FUSE	*/
		fuse_main(argc, argv, &pfs_oper, NULL);

	return 0;
}

